package cn.pkg.service.impl;

import cn.pkg.entities.Emp;
import cn.pkg.mapper.EmpMapper;
import cn.pkg.service.Empservice;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RSemaphore;
import org.redisson.client.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class EmpserviceImpl implements Empservice {
    @Resource
    private EmpMapper empMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private Redisson redisson;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void add(Emp emp) {
        empMapper.insert(emp);
    }
//    synchronized锁无法应对分布式（单机可用）
//    @Override
//    public Object getEmpById(Long id) {
////  先从缓存里面获取，如果没有，就查询SQL然后存入缓存
//        String key="user:"+id;
//         String a=new String("asdasdad");
//        Object userObj = redisTemplate.opsForValue().get(key);
//        if(userObj==null){
//            synchronized (a.getClass()){
//                userObj = redisTemplate.opsForValue().get(key);
//                if(userObj==null){
//                    log.debug("----------------查询MSQl数据库只有一次---------------------------------");
//                    userObj = empMapper.selectByPrimaryKey(id);
//                    redisTemplate.opsForValue().set(key,userObj);
//                }else{
//                    log.debug("查询缓存同步代码块,解决了300个漏网之鱼，从300次查询SQL改为查询Redis");
//                }
//            }
//        }else{
//            log.debug("----------------查询缓存1000次查询700次获取到了redis的值直接返回-------------------------");
//
//        }
//        return userObj;
//    }



//    自定义分布式锁,很失败，连单机锁的功能都无法实现
//    @Override
//    public Object getEmpById(Long id) {
//        String key="user"+id;
//        String lockKey="asd";
//        Object o=redisTemplate.opsForValue().get(key);
//        String clienId =UUID.randomUUID().toString();
//        try{
//            Boolean result =stringRedisTemplate.opsForValue().setIfAbsent(lockKey,"zhuge");
//            stringRedisTemplate.expire(lockKey,10,TimeUnit.SECONDS);
////            将上述两行代码搞成原子事务
////            stringRedisTemplate.opsForValue().setIfAbsent(lockKey,clienId,10,TimeUnit.SECONDS);
//            if(!result){
//                return "error";
//            }
//            if(o==null){
//                o=empMapper.selectByPrimaryKey(id);
//                redisTemplate.opsForValue().set(key,o);
//            }else{
//                System.out.println("查找缓存");
//            }
//        }finally {
//            stringRedisTemplate.delete(lockKey);
//        }
//        return o;
//    }


//    redisson框架锁
//    @Override
//    public Object getEmpById(Long id) {
//        String key="user"+id;
//        String lockKey="asd";
//        Object o=redisTemplate.opsForValue().get(key);
//        RReadWriteLock readWriteLock = redisson.getReadWriteLock(lockKey);
//        RLock rLock = readWriteLock.writeLock();
//        rLock.lock();
//        rLock.unlock();
//        RSemaphore park = redisson.getSemaphore("park");
//        boolean b = park.tryAcquire();
//        if(b){
//            System.out.println("或许信号量成功");
//        }
//        //释放信号量
//        RSemaphore parkRelse = redisson.getSemaphore("park");
//        parkRelse.release();
////        注意这里锁的获取，不要和缓存冲突
//        RLock redissonLock = redisson.getLock(lockKey);
//        if(o!=null){
//            System.out.println("首次过滤");
//            return o;
//        }
//        try{
//            redissonLock.lock(30,TimeUnit.SECONDS);
////            下面这行代码非常有必要，因为这是获取锁之后做的事情，如果获取锁之后，没有给o重新赋值的话，就会有300条漏网之鱼
//             o=redisTemplate.opsForValue().get(key);
//            System.out.println("第二次过滤");
////            if(o==null){
//                o=empMapper.selectByPrimaryKey(id);
//                redisTemplate.opsForValue().set(key,o);
//                System.out.println("查找数据库");
////            }else{
//                System.out.println("查找缓存");
////            }
//        }finally {
//            redissonLock.unlock();
//        }
//        return o;
//    }

    @Autowired
    private LettuceConnectionFactory redisConnectionFactory;


    @Override
    public Object getEmpById(Long id) {
        String key="user"+id;
        String lockKey="asd";
        Object o=redisTemplate.opsForValue().get(key);
        RReadWriteLock readWriteLock = redisson.getReadWriteLock(lockKey);
        RLock rLock = readWriteLock.writeLock();
        rLock.lock();
        rLock.unlock();
        RSemaphore park = redisson.getSemaphore("park");
        boolean b = park.tryAcquire();
        if(b){
            System.out.println("或许信号量成功");
        }
        //释放信号量
        RSemaphore parkRelse = redisson.getSemaphore("park");
        parkRelse.release();
        return "成功";
    }
//


    //    分布式锁，可以用分段锁提高性能，但是会有主从复制下，主宕机锁丢失问题，可用zookeper改进
}
